#ifndef _L_BV_TREE_120118_BOUNDING_VOLUME_H
#define _L_BV_TREE_120118_BOUNDING_VOLUME_H

#include <ltypes.h>
#include <lmacros.h>
#include <lvectors.h>
#include <ltriMesh.h>

LLIB_BEGIN
namespace geom {

/* The Axis Aligned Bounding Box */
class BV_AABB {
public:
    /* The default constructor */
    BV_AABB() {}

    /* The constructor with data */
    BV_AABB(const Vec3f& max, const Vec3f& min) : _max(max), _min(min) {}

    /* The constructor with single point */
    BV_AABB(const Vec3f& point) { Update(point); }

    /* The constructor with single triangle face */
    BV_AABB(const MeshFace& tri) { Update(tri); }

    /* Update bounding volume */
    inline void Update(const Vec3f& max, const Vec3f& min) { _max = max; _min = min; }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point);

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri);

    /* Merge */
    inline BV_AABB Merge(const BV_AABB& another) const { return Merge(*this, another); }
    static BV_AABB Merge(const BV_AABB& first, const BV_AABB& second);

    /* Intersect */
    inline Boolean Intersect(const BV_AABB& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_AABB& first, const BV_AABB& second);

private:
    Vec3f _max;
    Vec3f _min;
};

template <unsigned k>
class BV_kDOP;

typedef BV_AABB     BV_6DOP; // The AABB is actually a kind of 6-DOP
typedef BV_kDOP<8>  BV_8DOP;
typedef BV_kDOP<12> BV_12DOP;

typedef BV_kDOP<14> BV_14DOP;
typedef BV_kDOP<18> BV_18DOP;
typedef BV_kDOP<20> BV_20DOP;

typedef BV_kDOP<26> BV_26DOP;

/* The 8-DOP bounding volume.
 * using the axes (1,1,1),(1,1,-1), (1,-1,1), (-1,1,1)
 */
template <>
class BV_kDOP<8> {
private:
    typedef Vec<Float,4> Vec4f;
public:
    /* The defualt constructor */
    BV_kDOP<8>() {}

    /* The constructor with base data */
    BV_kDOP<8>(const Vec4f& max, const Vec4f& min) : _max(max), _min(min) {}

    /* The constructor with single point */
    BV_kDOP<8>(const Vec3f& point) { Update(point); }

    /* The constructor with single triangle face */
    BV_kDOP<8>(const MeshFace& tri) { Update(tri); }

    /* Update BV */
    inline void Update(const Vec4f& max, const Vec4f& min) { _max = max; _min = min; }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point);

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri);

    /* Merge */
    inline BV_kDOP<8> Merge(const BV_kDOP<8>& another) const { return Merge(*this, another); }
    static BV_kDOP<8> Merge(const BV_kDOP<8>& first, const BV_kDOP<8>& second);

    /* Intersect */
    inline Boolean Intersect(const BV_kDOP<8>& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_kDOP<8>& first, const BV_kDOP<8>& second);

private:
    Vec4f _max;
    Vec4f _min;
};

/* The 12-DOP bounding volume.
 * using the axes (1,1,0), (1,-1,0), (1,0,1), (1,0,-1), (0,1,1), (0,1,-1)
 */
template <>
class BV_kDOP<12> {
private:
    typedef Vec<Float,6> Vec6f;
public:
    /* The defualt constructor */
    BV_kDOP<12>() {}

    /* The constructor with base data */
    BV_kDOP<12>(const Vec6f& max, const Vec6f& min) : _max(max), _min(min) {}

    /* The constructor with single point */
    BV_kDOP<12>(const Vec3f& point) { Update(point); }

    /* The constructor with single triangle face */
    BV_kDOP<12>(const MeshFace& tri) { Update(tri); }

    /* Update BV */
    inline void Update(const Vec6f& max, const Vec6f& min) { _max = max; _min = min; }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point);

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri);

    /* Merge */
    inline BV_kDOP<12> Merge(const BV_kDOP<12>& another) const { return Merge(*this, another); }
    static BV_kDOP<12> Merge(const BV_kDOP<12>& first, const BV_kDOP<12>& second);

    /* Intersect */
    inline Boolean Intersect(const BV_kDOP<12>& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_kDOP<12>& first, const BV_kDOP<12>& second);

private:
    Vec6f _max;
    Vec6f _min;
};

/* The 14-DOP bounding volume.
 * it's composed by 6-DOP and 8-DOP
 */
template <>
class BV_kDOP<14> {
public:
    /* The defualt constructor */
    BV_kDOP<14>() {}

    /* The constructor with base data */
    BV_kDOP<14>(const BV_6DOP& dop6, const BV_8DOP& dop8) : _dop6(dop6), _dop8(dop8) {}

    /* The constructor with single point */
    BV_kDOP<14>(const Vec3f& point) { _dop6.Update(point); _dop8.Update(point); }

    /* The constructor with single triangle face */
    BV_kDOP<14>(const MeshFace& tri) { _dop6.Update(tri); _dop8.Update(tri); }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point) { _dop6.Update(point); _dop8.Update(point); }

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri) { _dop6.Update(tri); _dop8.Update(tri); }

    /* Merge */
    inline BV_kDOP<14> Merge(const BV_kDOP<14>& another) const { return Merge(*this, another); }
    static BV_kDOP<14> Merge(const BV_kDOP<14>& first, const BV_kDOP<14>& second);

    /* Intersect */
    inline Boolean Intersect(const BV_kDOP<14>& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_kDOP<14>& first, const BV_kDOP<14>& second);

private:
    BV_6DOP _dop6;
    BV_8DOP _dop8;
};

/* The 18-DOP bounding volume.
 * it's composed by 6-DOP and 12-DOP
 */
template <>
class BV_kDOP<18> {
public:
    /* The defualt constructor */
    BV_kDOP<18>() {}

    /* The constructor with base data */
    BV_kDOP<18>(const BV_6DOP& dop6, const BV_12DOP& dop12) : _dop6(dop6), _dop12(dop12) {}

    /* The constructor with single point */
    BV_kDOP<18>(const Vec3f& point) { _dop6.Update(point); _dop12.Update(point); }

    /* The constructor with single triangle face */
    BV_kDOP<18>(const MeshFace& tri) { _dop6.Update(tri); _dop12.Update(tri); }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point) { _dop6.Update(point); _dop12.Update(point); }

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri) { _dop6.Update(tri); _dop12.Update(tri); }

    /* Merge */
    inline BV_kDOP<18> Merge(const BV_kDOP<18>& another) const { return Merge(*this, another); }
    static BV_kDOP<18> Merge(const BV_kDOP<18>& first, const BV_kDOP<18>& second);

    /* Intersect */
    inline Boolean Intersect(const BV_kDOP<18>& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_kDOP<18>& first, const BV_kDOP<18>& second);

private:
    BV_6DOP  _dop6;
    BV_12DOP _dop12;
};

/* The 20-DOP bounding volume.
 * it's composed by 8-DOP and 12-DOP
 */
template <>
class BV_kDOP<20> {
public:
    /* The defualt constructor */
    BV_kDOP<20>() {}

    /* The constructor with base data */
    BV_kDOP<20>(const BV_8DOP& dop8, const BV_12DOP& dop12) : _dop8(dop8), _dop12(dop12) {}

    /* The constructor with single point */
    BV_kDOP<20>(const Vec3f& point) { _dop8.Update(point); _dop12.Update(point); }

    /* The constructor with single triangle face */
    BV_kDOP<20>(const MeshFace& tri) { _dop8.Update(tri); _dop12.Update(tri); }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point) { _dop8.Update(point); _dop12.Update(point); }

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri) { _dop8.Update(tri); _dop12.Update(tri); }

    /* Merge */
    inline BV_kDOP<20> Merge(const BV_kDOP<20>& another) const { return Merge(*this, another); }
    static BV_kDOP<20> Merge(const BV_kDOP<20>& first, const BV_kDOP<20>& second);

    /* Intersect */
    inline Boolean Intersect(const BV_kDOP<20>& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_kDOP<20>& first, const BV_kDOP<20>& second);

private:
    BV_8DOP  _dop8;
    BV_12DOP _dop12;
};

/* The 26-DOP bounding volume.
 * it's composed by 6-DOP, 8-DOP and 12-DOP
 */
template <>
class BV_kDOP<26> {
public:
    /* The defualt constructor */
    BV_kDOP<26>() {}

    /* The constructor with base data */
    BV_kDOP<26>(const BV_6DOP& dop6, const BV_8DOP& dop8, const BV_12DOP& dop12) : _dop6(dop6), _dop8(dop8), _dop12(dop12) {}

    /* The constructor with single point */
    BV_kDOP<26>(const Vec3f& point) { _dop6.Update(point); _dop8.Update(point); _dop12.Update(point); }

    /* The constructor with single triangle face */
    BV_kDOP<26>(const MeshFace& tri) { _dop6.Update(tri); _dop8.Update(tri); _dop12.Update(tri); }

    /* Update bounding volume using single point */
    void Update(const Vec3f& point) { _dop6.Update(point); _dop8.Update(point); _dop12.Update(point); }

    /* Update bounding volume using single triangle face */
    void Update(const MeshFace& tri) { _dop6.Update(tri); _dop8.Update(tri); _dop12.Update(tri); }

    /* Merge */
    inline BV_kDOP<26> Merge(const BV_kDOP<26>& another) const { return Merge(*this, another); }
    static BV_kDOP<26> Merge(const BV_kDOP<26>& first, const BV_kDOP<26>& second);

    /* Intersect */
    inline Boolean Intersect(const BV_kDOP<26>& another) const { return Intersect(*this, another); }
    static Boolean Intersect(const BV_kDOP<26>& first, const BV_kDOP<26>& second);

private:
    BV_6DOP  _dop6;
    BV_8DOP  _dop8;
    BV_12DOP _dop12;
};

} // end of namespace geom
LLIB_END

#endif
